永続的リクエストで起動された EC2 スポットインスタンスを停止後に開始しようとすると IncorrectSpotRequestState エラーが出た時の対処方法
困っていた内容
永続的リクエストで起動された EC2 スポットインスタンスを AWS CLI の stop-instances コマンドで停止後、start-instances コマンドで開始しようとすると、下記のエラーが発生し開始することができません。
An error occurred (IncorrectSpotRequestState) when calling the StartInstances operation: You can't start the Spot Instance 'i-xxxxxxxxxxxxxxxxx' because the associated Spot Instance request is not in an appropriate state to support start.
インスタンスが停止していることは、describe-instances コマンドで確認しています。 このエラーを解消するにはどうすればいいでしょうか。
どう対応すればいいの?
このエラーは、EC2 スポットインスタンスを起動したスポットリクエストの状態が "disabled" ではないために発生しています。 スポットリクエストの状態が "disabled" となったことを確認してから、EC2 スポットインスタンスの開始をお試しください。
やってみた
まず、下記のブログの手順で、マネジメントコンソールから EC2 スポットインスタンスを永続的リクエストで起動します。
なお、永続的リクエストで起動された EC2 スポットインスタンスは、停止・開始ができるのですが、以下の制約や条件があります。
制約事項
- スポットインスタンスを停止できるのは、そのインスタンスが、
persistent
なスポットインスタンスリクエストから起動された場合だけです。- 関連するスポットインスタンスリクエストがキャンセルされている場合は、スポットインスタンス を停止することはできません。スポットインスタンスリクエストがキャンセルされた場合は、スポットインスタンスを終了することのみ可能です。
- フリート、起動グループ、またはアベイラビリティーゾーングループの一部であるスポットインスタンスは停止できません。
前提条件
スポットインスタンスは、次の場合にのみ開始できます。
- スポットインスタンスを手動で停止している。
- スポットインスタンスが EBS-backed インスタンスである。
- スポットインスタンスに使用可能な容量がある。
- スポット料金が上限価格より低くなっている。
また、スポットインスタンスリクエストは、下記の状態をとります。
スポットインスタンスリクエストは、次に示すいずれかの状態を取ります。
- open – リクエストは受理されるまで待機状態です。
- active – リクエストは受理されており、関連付けられたスポットインスタンスが存在します。
- failed – リクエストの 1 つ以上のパラメータが正しくありません。
- closed – スポットインスタンスは中断または終了されました。
- disabled – スポットインスタンスがユーザーにより停止されました。
- cancelled – このリクエストはユーザーによりキャンセルされたか、リクエストの有効期限が切れました。
そうこうするうちにインスタンスが起動しました。元気そうです。
スポットリクエストの状態は「active」になっています。
さて、ここから前記エラーが発生するときのインスタンスの状態やスポットリクエストの状態を確認していきますが、そのために下記のようなスクリプトを作ってみました。
#!/bin/bash # インスタンスの状態とスポットリクエストの状態を出力する関数 function output-state() { # インスタンスの状態出力 echo "インスタンスの状態" aws ec2 describe-instances --instance-ids $1 \ --query 'Reservations[0].Instances[0].{InstanceId: InstanceId, State: State.Name}' \ --output table # スポットリクエストの状態出力 echo "スポットリクエストの状態" aws ec2 describe-spot-instance-requests --spot-instance-request-ids $2 \ --query 'SpotInstanceRequests[0].{InstanceId: InstanceId, SpotInstanceRequestId: SpotInstanceRequestId, State: State}' \ --output table } # 引数として渡されたインスタンス ID とスポットリクエスト ID を変数に格納 instance_id=$1 spot_request_id=$2 # 日時出力 date output-state ${instance_id} ${spot_request_id} # インスタンスを停止する echo "インスタンス停止" aws ec2 stop-instances --instance-ids ${instance_id} \ --query 'StoppingInstances[0].{InstanceId: InstanceId, CurrentState: CurrentState.Name, PreviousState: PreviousState.Name}' \ --output table # 停止するまで待つ echo "停止中..." aws ec2 wait instance-stopped --instance-ids ${instance_id} echo -e "停止完了!\n" while : do # 日時出力 date output-state ${instance_id} ${spot_request_id} # インスタンスを開始する echo "インスタンス開始" aws ec2 start-instances --instance-ids ${instance_id} \ --query 'StartingInstances[0].{InstanceId: InstanceId, CurrentState: CurrentState.Name, PreviousState: PreviousState.Name}' \ --output table # start-instances コマンドの終了コードを変数に格納 result=$? # 終了コードが 0 (= start-instances がエラーになってない) ならループから抜ける if [ $result -eq 0 ]; then break fi # 改行する echo -e # 1秒待つ sleep 1s done # インスタンスの状態が running になるまで待つ echo "開始中..." aws ec2 wait instance-running --instance-ids ${instance_id} echo -e "開始完了!\n" output-state ${instance_id} ${spot_request_id}
では、スクリプトを実行してみます。
まず、インスタンスの状態が "running" で、スポットリクエストの状態が "active" のときにスポットインスタンスを停止します。
インスタンスが停止しました。
このときのインスタンスの状態は "stopped"、スポットリクエストの状態は "active" であり、この状態でインスタンスを開始しようとするとエラーが発生します。
インスタンスが停止しているだけでは開始できないようです。
このあとしばらく同じ状況が続きます。
状況が変わったのは、スポットリクエストの状態が "disabled" になったときです。
インスタンスの開始が成功し、インスタンスの状態が "running" になりました。
まとめ
このように、永続的リクエストで起動された EC2 スポットインスタンスを開始するには、インスタンスの状態が "stopped" になっているだけではなく、スポットリクエストの状態が "disabled" になっている必要があります。